/*******************************************************************************
 * Copyright (c) 2010, 2010 Xbeam Project and ChenZhiKong.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 *******************************************************************************/
package org.bellusoft.xbeam.framework;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.bellusoft.xbeam.contract.concurrent.ThreadSafe;
import org.osgi.framework.Constants;
import static org.bellusoft.xbeam.framework.XbeamConstants.*;

/**
 * Framework launch configuration
 */
@ThreadSafe
public class FrameworkConfig {
	
	//org.osgi.framework.storage
	private String storageRoot ; 
	
	//org.osgi.framework.storage.clean
	private StorageCleanPolicy storageClean ; 
	
	//org.osgi.framework.system.packages
	private String systemPackages ; 
	
	//org.osgi.framework.system.packages.extra
	private String systemPackagesExtra ; 
	
	//org.osgi.framework.bootdelegation
	private String bootdelegation ; 
	
	//org.osgi.framework.bundle.parent
	private BundleParent bundleParent ; 
	
	//org.osgi.framework.startlevel.beginning
	//TODO: still not initialized !!!
	private int frameworkStartLevel ; 
	
	//	1：xbeam.bundleStartLevel      用来描述Bundle默认的StartLevel ，每一个Bundle的StartLevel可能会被InitialBundles配置文件中的属性覆盖 ；
	//	2：xbeam.initialDir      用来描述初始Bundle所在的目录 ；
	//	3：xbeam.startSetting     用来描述Bundle的全局启动设置 ；
	//	4：xbeam.cacheDir    用来描述框架
	
	private int bundleStartLevel ; 
	
	private String initialDir ; 
	
	private AutoStartSetting startSetting ; 
	
	private List<InitialBundle> initialBundles ;
	
	private static String workingDirectory = System.getProperty("user.dir");
	
	static FrameworkConfig instance(Map<String,String> configuration) throws FrameworkConfigException{
		
		FrameworkConfig rt = new FrameworkConfig();
		
		rt.storageRoot = configuration.get(Constants.FRAMEWORK_STORAGE);
		if(rt.storageRoot==null){
			rt.storageRoot = workingDirectory + File.separator + XbeamConstants.Osgi_Storage_Default ; 
		}
		
		rt.storageClean = StorageCleanPolicy.parse(configuration.get(Constants.FRAMEWORK_STORAGE_CLEAN)) ; 
		
		rt.systemPackages = configuration.get(Constants.FRAMEWORK_SYSTEMPACKAGES);
		
		rt.systemPackagesExtra = configuration.get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
		
		rt.bootdelegation = configuration.get(Constants.FRAMEWORK_BOOTDELEGATION) ; 
		
		rt.bundleParent = BundleParent.parse(configuration.get(Constants.FRAMEWORK_BUNDLE_PARENT));
		
		rt.bundleStartLevel = parseStartLevel(configuration.get(XbeamConstants.Xbeam_Bundle_Start_Level)); 
		
		rt.initialDir = configuration.get(XbeamConstants.Xbeam_Initial_Bundle_Dir);
		if(rt.initialDir==null){
			rt.initialDir = workingDirectory + File.separator + XbeamConstants.Xbeam_Initial_Bundle_Dir_Default; 
		}
		
		rt.startSetting = AutoStartSetting.parse(configuration.get(XbeamConstants.Xbeam_Start_Setting));
		
		rt.initialBundles = parseInitialBundles(configuration.get(XbeamConstants.Xbeam_Initial_Bundle_Config));
		
		return rt ; 
	}
	
	/**
	 * @param string
	 * @return
	 * @throws FrameworkConfigException 
	 */
	//TODO: refactor to a class to make unit test easy 
	private static List<InitialBundle> parseInitialBundles(String value) throws FrameworkConfigException {
		String initialBundleConfig = value ; 
		File initialBundleDir = null ; 
		if(initialBundleConfig!=null&&!initialBundleConfig.trim().isEmpty()){
			initialBundleDir = new File(initialBundleConfig);
			//if xbeam.initial.bundle.dir exist, it must be a valid file path
			if(!initialBundleDir.exists()||!initialBundleDir.isFile()){
				throw new FrameworkConfigException("Initial bundles config file ["+initialBundleConfig+"] is not exist or is not a file.");  
			}
		}else{
			initialBundleConfig = workingDirectory + File.pathSeparator + XbeamConstants.Xbeam_Initial_Bundle_Dir_Default;
			initialBundleDir = new File(initialBundleConfig);
			//if default Initial bundles config file is not exist, just ignore
			if(!initialBundleDir.exists()||!initialBundleDir.isFile()){
				return Collections.emptyList();
			}
		}
		if(!initialBundleDir.canRead()){
			initialBundleDir.setReadable(true);
		}
		if(!initialBundleDir.canRead()){
			throw new FrameworkConfigException("Initial bundles config file ["+initialBundleConfig+"] can not be read.");
		}
		String fileEncoding = System.getProperty("file.encoding") ; 
		if(fileEncoding==null){
			fileEncoding = "UTF-8" ; 
		}
		BufferedReader configReader = null;
		try{
			configReader = new BufferedReader(new InputStreamReader(new FileInputStream(initialBundleDir),fileEncoding));
		}catch (Throwable t) {
			throw new FrameworkConfigException("Error when loading Initial bundles config file ["+initialBundleConfig+"]",t);
		}finally{
			if(configReader!=null){
				try {
					configReader.close();
				} catch (IOException e) {
				}
			}
		}
		
		List<InitialBundle> rt = new ArrayList<InitialBundle>() ; 
		
		String line;
		try {
			line = configReader.readLine();
			while(line != null){
				rt.add(InitialBundle.parse(value));
				line = configReader.readLine() ; 
			}
		} catch (Throwable t) {
			throw new FrameworkConfigException("Error when loading Initial bundles config file ["+initialBundleConfig+"]",t);
		}finally{
			try {
				configReader.close() ;
			} catch (IOException e) {
			} 
		}
		
		return rt;
	}

	private static int parseStartLevel(String value) {
		if(value==null||value.trim().isEmpty()){
			return XbeamConstants.Xbeam_Bundle_Start_Level_Default ; 
		}
		int rt ;
		try{
			rt = Integer.parseInt(value);
		}catch (NumberFormatException e) {
			throw new IllegalArgumentException(value+" is not a valid value of xbeam specific framework property "+XbeamConstants.Xbeam_Bundle_Start_Level+
			",it must be a integer bigger than 0");
		}
		if(rt<=0){
			throw new IllegalArgumentException(value+" is not a valid value of xbeam specific framework property "+XbeamConstants.Xbeam_Bundle_Start_Level+
			",it must be a integer bigger than 0");
		}
		return rt;
	}

	private FrameworkConfig() {
	}

	/**
	 * @return the bundleStartLevel
	 */
	public int getBundleStartLevel() {
		return bundleStartLevel;
	}

	/**
	 * @return the initialDir
	 */
	public String getInitialDir() {
		return initialDir;
	}

	/**
	 * @return the cacheDir
	 */
	public String getCacheDir() {
		return storageRoot;
	}

	/**
	 * @return the startSetting
	 */
	public AutoStartSetting getStartSetting() {
		return startSetting;
	}

	/**
	 * @return the initialBundles
	 */
	public List<InitialBundle> getInitialBundles() {
		return initialBundles;
	}

	/**
	 * @return the storageRoot
	 */
	public String getStorageRoot() {
		return storageRoot;
	}

	/**
	 * @return the storageClean
	 */
	public StorageCleanPolicy getStorageClean() {
		return storageClean;
	}

	/**
	 * @return the systemPackages
	 */
	public String getSystemPackages() {
		return systemPackages;
	}

	/**
	 * @return the systemPackagesExtra
	 */
	public String getSystemPackagesExtra() {
		return systemPackagesExtra;
	}

	/**
	 * @return the bootdelegation
	 */
	public String getBootdelegation() {
		return bootdelegation;
	}

	/**
	 * @return the bundleParent
	 */
	public BundleParent getBundleParent() {
		return bundleParent;
	}

	/**
	 * @return the frameworkStartLevel
	 */
	public int getFrameworkStartLevel() {
		return frameworkStartLevel;
	}

	

}
